/**
 * @ Author: luoqi
 * @ Create Time: 2024-08-02 03:24
 * @ Modified by: Your name
 * @ Modified time: 2025-08-11 23:02:25
 * @ Description:
 */


#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <pthread.h>
#include "qcli.h"
#include "qfsm.h"

static QCliObj cli;

#define ISARG(arg, str) (strcmp((arg), (str)) == 0)
#define QSH(...)    cli.print(__VA_ARGS__)

// static QFSM_CREATE(fsm);
static QFsm fsm;

static QFsmState state_1;
static QFsmState state_2;
static QFsmState state_3;

static bool s1_isfirst = true;
static bool s2_isfirst = true;
static bool s3_isfirst = true;

static void state_1_in(void *param)
{
    s1_isfirst = true;
    QSH(" ---state 1 in\r\n");
}

static QFsmResp state_1_cb(void *param)
{
    if(s1_isfirst) {
        s1_isfirst = false;
        QSH(" ---state 1 cb\r\n");
    }
    return QFSM_KEEP;
}

static void state_1_out(void *param)
{
    QSH(" ---state 1 out\r\n");
}

static void state_2_in(void *param)
{
    s2_isfirst = true;
    QSH(" ---state 2 in\r\n");
}

static QFsmResp state_2_cb(void *param)
{
    if(s2_isfirst) {
        s2_isfirst = false;
        QSH(" ---state 2 cb\r\n");
    }
    return QFSM_KEEP;
}

static void state_2_out(void *param)
{
    QSH(" ---state 2 out\r\n");
}

static void state_3_in(void *param)
{
    s3_isfirst = true;
    QSH(" ---state 3 in\r\n");
}

static QFsmResp state_3_cb(void *param)
{
    if(s3_isfirst) {
        s3_isfirst = false;
        QSH(" ---state 3 cb\r\n");
    }
    qfsm_skip(&fsm, "s2");
    return QFSM_KEEP;
}

static void state_3_out(void *param)
{
    QSH(" ---state 3 out\r\n");
}

static void fsm_hook(void *param)
{
    QSH(" ---hook\r\n");
}

static pthread_t _fsm_thread;
static void *_fsm_thread_hdl(void *arg)
{
    while(1) {
        qfsm_exec(&fsm);
        usleep(1e3);
    }
}

static QCliCmd _cmd_fsm;

static void _cmd_fsm_help(void)
{
    QSH(" -skip <state>\r\n");
}

static int _cmd_fsm_hdl(int argc, char **argv)
{
    if(argc == 1) {
        QSH(" current state: %s\r\n", fsm.current->name);
        QSH(" state 1 next state: %s\r\n", state_1.next->name);
        QSH(" state 2 next state: %s\r\n", state_2.next->name);
        QSH(" state 3 next state: %s\r\n", state_3.next->name);

        qfsm_dump(&fsm, printf);
    } else if(ISARG(argv[1], "skip") && argc == 3) {
        qfsm_skip(&fsm, argv[2]);
    } else {
        _cmd_fsm_help();
    }
    return 0;
}

int main()
{
    qfsm_init(&fsm);

    qfsm_add(&fsm, &state_1, "s1", "s2", state_1_cb, state_1_in, state_1_out);
    qfsm_add(&fsm, &state_2, "s2", "s3", state_2_cb, state_2_in, state_2_out);
    qfsm_add(&fsm, &state_3, "s3", "s1", state_3_cb, state_3_in, state_3_out);
    qfsm_hook_set(&fsm, fsm_hook);

    qfsm_setup(&fsm, "s1", NULL);

    pthread_create(&_fsm_thread, NULL, _fsm_thread_hdl, NULL);
    pthread_detach(_fsm_thread);

    qcli_init(&cli, printf);
    qcli_add(&cli, &_cmd_fsm, "fsm", _cmd_fsm_hdl, "fsm test commands");
    qcli_title(&cli);
    char ch;
    while(true) {
        if(system("stty raw -echo") < 0) {
            QSH(" #! system call error !\r\n");
        }
        ch = getchar();
        ch = (ch == 127) ? 8 : ch;
        if(ch != 3) {
            qcli_exec(&cli, ch);
        } else {
            if(system("stty -raw echo") < 0) {
                QSH(" #! system call error !\r\n");
            }
            QSH("\33[2K");
            QSH("\033[H\033[J");
            QSH(" \r\n#! QSH input thread closed !\r\n\r\n");
            return 0;
        }
    }
    return 0;
}
